function fcn_mLoss_split0_Train(varargin)
%FNCTRAIN Train FCN model using MatConvNet
% run matconvnet/matlab/vl_setupnn ;
% addpath matconvnet/examples ;
% experiment and data paths

opts.expDir = './mSplit' ;
opts.dataDir = '../data/voc12' ;
opts.sourceModelPath = '../data/models/imagenet-vgg-verydeep-16.mat' ;
[opts, varargin] = vl_argparse(opts, varargin) ;

% experiment setup
opts.imdbPath = fullfile(opts.expDir, 'imdb.mat') ;
opts.imdbStatsPath = fullfile(opts.expDir, 'imdbStats.mat') ;
opts.vocEdition = '12' ;
opts.vocAdditionalSegmentations = true ;

opts.numFetchThreads = 1 ; % not used yet
% training options (SGD)
opts.train = struct('gpus', [1]) ;
[opts, varargin] = vl_argparse(opts, varargin) ;

trainOpts.batchSize =  20;
trainOpts.numSubBatches = 20 ;
trainOpts.continue = true ;
trainOpts.gpus = [1] ;
trainOpts.prefetch = true ;
trainOpts.expDir = opts.expDir ;
trainOpts.learningRate = [0.0001* ones(1,50)] ;
trainOpts.numEpochs = numel(trainOpts.learningRate) ;


% Setup data
% Get PASCAL VOC 12 segmentation dataset plus Berkeley's additional segmentations
if exist(opts.imdbPath)
  imdb = load(opts.imdbPath) ;
else
  imdb = vocSetup('dataDir', opts.dataDir, 'edition', opts.vocEdition, 'includeTest', false, 'includeSegmentation', true, 'includeDetection', false) ;
  if opts.vocAdditionalSegmentations
    imdb = vocSetupAdditionalSegmentations(imdb, 'dataDir', opts.dataDir) ;
  end
  mkdir(opts.expDir) ;
  save(opts.imdbPath, '-struct', 'imdb') ;
end

% Get training and test/validation subsets
train = find(imdb.images.set == 1 & imdb.images.segmentation) ;
val = find(imdb.images.set == 2 & imdb.images.segmentation) ;

% Get dataset statistics
if exist(opts.imdbStatsPath)
  stats = load(opts.imdbStatsPath) ;
else
  stats = getDatasetStatistics(imdb) ;
  save(opts.imdbStatsPath, '-struct', 'stats') ;
end

% -------------------------------------------------------------------------
% Setup model
% Get initial model from VGG-VD-16
net = vggFCN_fc678_mLoss_split0_init() ;


net.meta.normalization.rgbMean = stats.rgbMean ;
net.meta.classes = imdb.classes.name ;

% Train
% Setup data fetching options
bopts.numThreads = opts.numFetchThreads ;
bopts.labelStride = 1 ;
bopts.labelOffset = 1 ;
bopts.classWeights = ones(1,21,'single') ;
bopts.rgbMean = stats.rgbMean ;
bopts.useGpu = numel(opts.train.gpus) > 0 ;

% Launch SGD
info = cnn_train_dag1(net, imdb, getBatchWrapper(bopts), trainOpts, 'train', train, 'val', val, opts.train) ;

function fn = getBatchWrapper(opts)
fn = @(imdb,batch) getBatch_Unet_noCrop(imdb,batch,opts,'prefetch',nargout==0) ;
